﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Onshi.POS.AccesoDatos;
using Onshi.POS.AccesoDatos.Interfaces;
using Onshi.POS.Modelo.Entidades;
using Onshi.POS.Modelo.Objetos;

namespace Onshi.POS.Repositorios
{
    public class RepositorioCliente : RepositorioEntidad<Cliente, Int32>
    {
        #region Constructores

        public RepositorioCliente()
            : base()
        {
            servicioDatosCliente = new ServicioDatosCliente();
            repositorioTipoIva = new RepositorioTipoIva();
            repositorioRubroCliente = new RepositorioRubroCliente();
            repositorioTipoDomicilio = new RepositorioTipoDomicilio();
            repositorioBarrio = new RepositorioBarrio();
            repositorioTipoTelefono = new RepositorioTipoTelefono();
            repositorioTipoMensajeriaInstantanea = new RepositorioTipoMensajeriaInstantanea();
            repositorioVendedor = new RepositorioVendedor();
            repositorioListaPrecioVenta = new RepositorioListaPrecioVenta();
            repositorioTipoFormaPago = new RepositorioTipoFormaPago();
        }

        #endregion

        #region Atributos

        private IServicioDatosCliente servicioDatosCliente;
        private RepositorioTipoIva repositorioTipoIva;
        private RepositorioListaPrecioVenta repositorioListaPrecioVenta;
        private RepositorioRubroCliente repositorioRubroCliente;
        private RepositorioTipoDomicilio repositorioTipoDomicilio;
        private RepositorioTipoTelefono repositorioTipoTelefono;
        private RepositorioTipoMensajeriaInstantanea repositorioTipoMensajeriaInstantanea;
        private RepositorioBarrio repositorioBarrio;
        private RepositorioVendedor repositorioVendedor;
        private RepositorioTipoFormaPago repositorioTipoFormaPago;

        #endregion

        #region Propiedades

        private RepositorioListaPrecioVenta RepositorioListaPrecioVenta
        {
            get { return repositorioListaPrecioVenta; }
        }

        private RepositorioTipoFormaPago RepositorioTipoFormaPago
        {
            get { return repositorioTipoFormaPago; }
        }

        private IServicioDatosCliente ServicioDatosCliente
        {
            get { return servicioDatosCliente; }
        }

        private RepositorioBarrio RepositorioBarrio
        {
            get { return repositorioBarrio; }
        }

        private RepositorioTipoTelefono RepositorioTipoTelefono
        {
            get { return repositorioTipoTelefono; }
        }

        private RepositorioTipoIva RepositorioTipoIva
        {
            get { return repositorioTipoIva; }
        }

        private RepositorioRubroCliente RepositorioRubroCliente
        {
            get { return repositorioRubroCliente; }
        }

        private RepositorioTipoDomicilio RepositorioTipoDomicilio
        {
            get { return repositorioTipoDomicilio; }
        }

        private RepositorioTipoMensajeriaInstantanea RepositorioTipoMensajeriaInstantanea
        {
            get { return repositorioTipoMensajeriaInstantanea; }
        }

        private RepositorioVendedor RepositorioVendedor
        {
            get { return repositorioVendedor; }
        }

        #endregion

        #region Metodos

        private ClienteTipoFormaPago FilaAClienteTipoFormaPago(DataRow fila, Cliente cliente)
        {
            var clienteTipoFormaPago = new ClienteTipoFormaPago();
            clienteTipoFormaPago.Id = (Int32)fila["IdClienteTipoFormaPago"];
            clienteTipoFormaPago.TipoFormaPago = RepositorioTipoFormaPago.DevolverPorId((Byte)fila["IdTipoFormaPago"]);
            clienteTipoFormaPago.TienePermiso = (Boolean)fila["TienePermiso"];
            clienteTipoFormaPago.Cliente = cliente;
            return clienteTipoFormaPago;
        }

        private List<ClienteTipoFormaPago> TablaAListaClientesTiposFormasPagos(DataTable tabla, Cliente cliente)
        {
            var lista = new List<ClienteTipoFormaPago>();
            foreach (DataRow fila in tabla.Rows)
                lista.Add(FilaAClienteTipoFormaPago(fila, cliente));
            return lista;
        }

        protected override Cliente FilaAEntidad(DataRow fila)
        {
            var cliente = new Cliente();
            cliente.Id = (Int32)fila["IdCliente"];
            cliente.Codigo = (String)fila["Codigo"];
            cliente.Nombre = (String)fila["Nombre"];
            cliente.Cuit = (String)fila["Cuit"];
            cliente.SitioWeb = (String)fila["SitioWeb"];
            cliente.Email = (String)fila["Email"];
            cliente.MensajeriaInstantanea = (String)fila["MensajeriaInstantanea"];
            cliente.DescuentoRecargo = (Decimal)fila["DescuentoRecargo"];
            cliente.LimiteDeuda = (Decimal)fila["LimiteDeuda"];
            cliente.EstaEliminado = (Boolean)fila["EstaEliminado"];
            cliente.Rubro = RepositorioRubroCliente.DevolverPorId((Int32)fila["IdRubroCliente"]);
            cliente.TipoIva = RepositorioTipoIva.DevolverPorId((Byte)fila["IdTipoIva"]);
            cliente.TipoMensajeriaInstantanea = RepositorioTipoMensajeriaInstantanea.DevolverPorId((Byte)fila["IdTipoMensajeriaInstantanea"]);
            cliente.Vendedor = RepositorioVendedor.DevolverPorId((Int32)fila["IdVendedor"]);
            cliente.ListaPrecioVenta = RepositorioListaPrecioVenta.DevolverPorId((Int32)fila["IdListaPrecioVenta"]);
            if (fila.Table.Columns.Contains("TieneDomicilios"))
                cliente.TieneDomicilios = (Boolean)fila["TieneDomicilios"];
            if (fila.Table.Columns.Contains("TieneImagen"))
                cliente.TieneImagen = (Boolean)fila["TieneImagen"];
            if (fila.Table.Columns.Contains("TieneObservacion"))
                cliente.TieneObservacion = (Boolean)fila["TieneObservacion"];
            if (fila.Table.Columns.Contains("TieneTelefonos"))
                cliente.TieneTelefonos = (Boolean)fila["TieneTelefonos"];
            return cliente;
        }

        private DetalleCliente FilaADetalle(DataRow fila, Cliente cliente)
        {
            var detalle = new DetalleCliente();
            detalle.Cliente = cliente;
            detalle.Observacion = (String)fila["Observacion"];
            if (fila["Imagen"] != DBNull.Value)
                detalle.Imagen = ManejoImagen.ByteAImagen((Byte[])fila["Imagen"]);
            return detalle;
        }

        private DomicilioCliente FilaADomicilio(DataRow fila, Cliente cliente)
        {
            var domicilio = new DomicilioCliente();
            domicilio.Cliente = cliente;
            domicilio.Id = (Int32)fila["IdDomicilioCliente"];
            domicilio.Tipo = RepositorioTipoDomicilio.DevolverPorId((Byte)fila["IdTipoDomicilio"]);
            domicilio.Barrio = RepositorioBarrio.DevolverPorId((Int32)fila["IdBarrio"]);
            domicilio.Calle = (String)fila["Calle"];
            domicilio.Numero = (String)fila["Numero"];
            domicilio.Piso = (String)fila["Piso"];
            domicilio.Departamento = (String)fila["Departamento"];
            domicilio.Observacion = (String)fila["Observacion"];
            return domicilio;
        }

        private List<DomicilioCliente> TablaAListaDomicilios(DataTable tabla, Cliente cliente)
        {
            var lista = new List<DomicilioCliente>();
            foreach (DataRow fila in tabla.Rows)
                lista.Add(FilaADomicilio(fila, cliente));
            return lista;
        }

        private TelefonoCliente FilaATelefono(DataRow fila, Cliente cliente)
        {
            var telefono = new TelefonoCliente();
            telefono.Cliente = cliente;
            telefono.Id = (Int32)fila["IdTelefonoCliente"];
            telefono.Tipo = RepositorioTipoTelefono.DevolverPorId((Byte)fila["IdTipoTelefono"]);
            telefono.CodigoArea = (String)fila["CodigoArea"];
            telefono.Numero = (String)fila["Numero"];
            telefono.Observacion = (String)fila["Observacion"];
            return telefono;
        }

        private List<TelefonoCliente> TablaAListaTelefonos(DataTable tabla, Cliente cliente)
        {
            var lista = new List<TelefonoCliente>();
            foreach (DataRow fila in tabla.Rows)
                lista.Add(FilaATelefono(fila, cliente));
            return lista;
        }

        public override Cliente DevolverPorId(Int32 id)
        {
            var entidad = entidades.Where(x => x.Id == id).FirstOrDefault();
            if (entidad == null)
                using (var ds = ServicioDatosCliente.Clientes_DevolverPorId(id))
                    if (ds.Tables[0].Rows.Count != 0)
                    {
                        entidad = FilaAEntidad(ds.Tables[0].Rows[0]);
                        entidad.TiposFormasPagos = TablaAListaClientesTiposFormasPagos(ds.Tables[1], entidad);
                        entidades.Add(entidad);
                    }
            return entidad;
        }

        public Cliente DevolverPorIdConDetalleDomiciliosTelefonos(Int32 id)
        {
            var entidad = entidades.Where(x => x.Id == id
                && x.Detalle != null
                && x.Domicilios != null
                && x.Telefonos != null).FirstOrDefault();
            if (entidad == null)
                using (var ds = ServicioDatosCliente.Clientes_DevolverPorIdConDetalleDomiciliosTelefonos(id))
                    if (ds.Tables[0].Rows.Count != 0)
                    {
                        entidad = FilaAEntidad(ds.Tables[0].Rows[0]);
                        entidad.TiposFormasPagos = TablaAListaClientesTiposFormasPagos(ds.Tables[1], entidad);
                        entidad.Detalle = FilaADetalle(ds.Tables[2].Rows[0], entidad);
                        entidad.Domicilios = TablaAListaDomicilios(ds.Tables[3], entidad);
                        entidad.Telefonos = TablaAListaTelefonos(ds.Tables[4], entidad);
                        entidades.Add(entidad);
                    }
            return entidad;
        }

        public Cliente DevolverPorCodigo(String codigo)
        {
            var entidad = entidades.Where(x => x.Codigo == codigo).FirstOrDefault();
            if (entidad == null)
                using (var ds = ServicioDatosCliente.Clientes_DevolverPorCodigo(codigo))
                    if (ds.Tables[0].Rows.Count != 0)
                    {
                        entidad = FilaAEntidad(ds.Tables[0].Rows[0]);
                        entidad.TiposFormasPagos = TablaAListaClientesTiposFormasPagos(ds.Tables[1], entidad);
                        entidades.Add(entidad);
                    }
            return entidad;
        }

        public Cliente DevolverPorCodigoConDetalleDomiciliosTelefonos(String codigo)
        {
            var entidad = entidades.Where(x => x.Codigo == codigo
                && x.Detalle != null
                && x.Domicilios != null
                && x.Telefonos != null).FirstOrDefault();
            if (entidad == null)
                using (var ds = ServicioDatosCliente.Clientes_DevolverPorCodigoConDetalleDomiciliosTelefonos(codigo))
                    if (ds.Tables[0].Rows.Count != 0)
                    {
                        entidad = FilaAEntidad(ds.Tables[0].Rows[0]);
                        entidad.TiposFormasPagos = TablaAListaClientesTiposFormasPagos(ds.Tables[1], entidad);
                        entidad.Detalle = FilaADetalle(ds.Tables[2].Rows[0], entidad);
                        entidad.Domicilios = TablaAListaDomicilios(ds.Tables[3], entidad);
                        entidad.Telefonos = TablaAListaTelefonos(ds.Tables[4], entidad);
                        entidades.Add(entidad);
                    }
            return entidad;
        }

        public List<Cliente> DevolverTodos()
        {
            using (var ds = ServicioDatosCliente.Clientes_DevolverTodos())
            {
                entidades = TablaALista(ds.Tables[0]);
                foreach (var cliente in entidades)
                {
                    var tiposFormasPagos = ds.Tables[1].AsEnumerable().Where(x => (Int32)x["IdCliente"] == cliente.Id).CopyToDataTable();
                    cliente.TiposFormasPagos = TablaAListaClientesTiposFormasPagos(tiposFormasPagos, cliente);
                }
            }
            return entidades;
        }

        public List<Cliente> DevolverTodosConDetalleDomiciliosTelefonos()
        {
            using (var ds = ServicioDatosCliente.Clientes_DevolverTodosConDetalleDomiciliosTelefonos())
                if (ds.Tables[0].Rows.Count != 0)
                {
                    entidades = TablaALista(ds.Tables[0]);
                    foreach (var cliente in entidades)
                    {
                        var tiposFormasPagos = ds.Tables[1].AsEnumerable().Where(x => (Int32)x["IdCliente"] == cliente.Id).CopyToDataTable();
                        cliente.TiposFormasPagos = TablaAListaClientesTiposFormasPagos(tiposFormasPagos, cliente);
                        var detalle = ds.Tables[2].AsEnumerable().Where(x => (Int32)x["IdCliente"] == cliente.Id).CopyToDataTable();
                        cliente.Detalle = FilaADetalle(detalle.Rows[0], cliente);
                        var domicilios = ds.Tables[3].AsEnumerable().Where(x => (Int32)x["IdCliente"] == cliente.Id).CopyToDataTable();
                        cliente.Domicilios = TablaAListaDomicilios(domicilios, cliente);
                        var telefonos = ds.Tables[4].AsEnumerable().Where(x => (Int32)x["IdCliente"] == cliente.Id).CopyToDataTable();
                        cliente.Telefonos = TablaAListaTelefonos(telefonos, cliente);
                    }
                }
            return entidades;
        }

        public void Insertar(Cliente cliente)
        {
            cliente.Id = ServicioDatosCliente.Clientes_Insertar(cliente.Codigo, cliente.Nombre, cliente.Email, cliente.SitioWeb, cliente.DescuentoRecargo, cliente.LimiteDeuda, cliente.Cuit, cliente.MensajeriaInstantanea, cliente.Rubro.Id, cliente.TipoIva.Id, cliente.ListaPrecioVenta.Id, cliente.Vendedor.Id, cliente.TipoMensajeriaInstantanea.Id);
        }

        public void Modificar(Cliente cliente)
        {
            ServicioDatosCliente.Clientes_Modificar(cliente.Id, cliente.Codigo, cliente.Nombre, cliente.Email, cliente.SitioWeb, cliente.DescuentoRecargo, cliente.LimiteDeuda, cliente.Cuit, cliente.MensajeriaInstantanea, cliente.Rubro.Id, cliente.TipoIva.Id, cliente.ListaPrecioVenta.Id, cliente.Vendedor.Id, cliente.TipoMensajeriaInstantanea.Id);
        }

        public void ModificarRubros(RubroCliente rubrocliente, RubroCliente rubroclienteNuevo)
        {
            //ServicioDatosVendedor.Vendedores_ModificarRubrosVendedores(rubroVendedor.Id, rubroVendedorNuevo.Id);
        }

        public void Eliminar(Cliente cliente)
        {
            ServicioDatosCliente.Clientes_Eliminar(cliente.Id);
            cliente.EstaEliminado = true;
        }

        public void Habilitar(Cliente cliente)
        {
            ServicioDatosCliente.Clientes_Habilitar(cliente.Id);
            cliente.EstaEliminado = false;
        }

        public void EliminarDomiciliosPorCliente(Cliente cliente)
        {
            ServicioDatosCliente.DomiciliosClientes_EliminarPorCliente(cliente.Id);
        }

        public void InsertarDomicilio(DomicilioCliente domicilio)
        {
            domicilio.Id = ServicioDatosCliente.DomiciliosClientes_Insertar(domicilio.Cliente.Id, domicilio.Tipo.Id, domicilio.Barrio.Id, domicilio.Calle, domicilio.Numero, domicilio.Piso, domicilio.Departamento, domicilio.Observacion);
        }

        public void EliminarTelefonosPorCliente(Cliente cliente)
        {
            ServicioDatosCliente.TelefonosClientes_EliminarPorCliente(cliente.Id);
        }

        public void InsertarTelefono(TelefonoCliente telefono)
        {
            telefono.Id = ServicioDatosCliente.TelefonosClientes_Insertar(telefono.Cliente.Id, telefono.Tipo.Id, telefono.CodigoArea, telefono.Numero, telefono.Observacion);
        }

        public void InsertarDetalle(DetalleCliente detalle)
        {
            ServicioDatosCliente.ClientesDetalles_Insertar(detalle.Cliente.Id, detalle.Observacion, ManejoImagen.ImagenAByte(detalle.Imagen));
        }

        public void ModificarDetalle(DetalleCliente detalle)
        {
            ServicioDatosCliente.ClientesDetalles_Modificar(detalle.Cliente.Id, detalle.Observacion, ManejoImagen.ImagenAByte(detalle.Imagen));
        }

        public void ModificarDomiciliosBarrios(Barrio barrio, Barrio barrioNuevo)
        {
            //ServicioDatosCliente.DomiciliosVendedores_ModificarBarrios(barrio.Id, barrioNuevo.Id);
        }

        public void EliminarClientesTiposFormasPagosPorCliente(Cliente cliente)
        {
            ServicioDatosCliente.ClientesTiposFormasPagos_EliminarPorCliente(cliente.Id);
        }

        public void InsertarClienteTipoFormaPago(ClienteTipoFormaPago clienteTipoFormaPago)
        {
            clienteTipoFormaPago.Id = ServicioDatosCliente.ClientesTiposFormasPagos_Insertar(clienteTipoFormaPago.Cliente.Id, clienteTipoFormaPago.TipoFormaPago.Id);
        }

        #endregion
    }
}